/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief Internal interface of class parser and parse tree.
 *
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#pragma once

#ifndef AMCC__PARSER_INNER_H
#define AMCC__PARSER_INNER_H

#include <stdlib.h>

#include "../../include/amcc_list.h"
#include "../../include/amcc_error.h"
#include "../../include/amcc_log.h"
#include "../../include/parser.h"
#include "../../include/tree.h"

AMCC_DECL_BEGIN

// -----------------------------------------------------------------------
//  Internal API of class parse tree
//

/**
 * @brief  Creates a new tree node marked with a non-terminal
 * @param nt   an enumerator of non-terminal
 * @param productionId   production id, a positive number, and
 *           it may be reset by tree_reset_production()
 * @return On success, return a pointer to new node.
 *         On failure(memory allocation, bad argument), return NULL.
 */
extern t_tree_ptr  tree_new_parent(EnumNonTerminal nt, int productionId);

/**
 * @brief  Appends a child node to the parent.
 * @param parent  pointer to the parent node
 * @param child   pointer to the child node tobe appended
 * @return Return true if appending is successful.
 */
extern bool tree_add_child(t_tree_ptr parent, t_tree_ptr child);

/**
 * @brief  Creates a new tree node marked with a terminal.
 * @param tokenPtr   pointer to a token
 * @return On success, return a pointer to new node.
 *         On failure(memory allocation), return NULL.
 */
extern t_tree_ptr  tree_new_leaf(t_token_ptr tokenPtr);

/**
 * @brief  Creates a new tree node marked with EPSILON.
 * @param positionPtr   pointer to a position object
 * @return On success, return a pointer to new node.
 *         On failure(memory allocation), return NULL.
 */
 extern t_tree_ptr  tree_new_epsilon(t_position_ptr positionPtr);

/**
 * @brief Reset the production id of a tree node marked with non-terminal.
 * @param ntNode  pointer to tree node marked with non-terminal
 * @param prdId   production id, a positive number
 * @note  Do nothing if any argument is invalid.
 */
extern void tree_reset_production(t_tree_ptr ntNode, int prdId);


// -----------------------------------------------------------------------
//  Helpers of class Parser
//

// Consume current token and prefetch next token(LT1)
extern void parser_fetch_token(t_parser_ptr pThis);

// Whether the next Kth token is a type name
extern bool parser_isTypename(t_parser_ptr pThis, int K);

// Show trace message when a deduction from a non-terminal started ,
// in other words, a Recursive-Descent-Function begins to run.
extern void enter_nonterminal(t_parser_ptr pThis, EnumNonTerminal ntId,
                              t_tree_ptr root);

// Show trace message when a deduction is done,
// in other words, a Recursive-Descent-Function is done.
extern void exit_nonterminal(t_parser_ptr pThis,  EnumNonTerminal ntId,
                             t_tree_ptr root);

// Report a bad-token error, and report what is expected.
// If it is not null,  expectedDesc is shown;
// else,  name of expectedByGrammar is shown.
extern void parser_report_badtoken(t_parser_ptr pThis,
                                   t_token_ptr tokenPtr,
                                   EnumTokenKind  expectedByGrammar,
                                   const char * expectedDesc);

// Try to match the next token according to grammar.
// On matched, consume it, prefetch it's next token and return
//    the parser tree node(a leaf) for matched token.
// On unmatched, report bad-token error and return null.
extern t_tree_ptr parser_match(t_parser_ptr pThis,
                               EnumTokenKind  expectedByGrammar);

/**
 * @brief Discard one or more tokens on syntax error,
 *        until an input token is one of "synchronizing tokens".
 * @param firstSet   the set of FIRST of a non-terminal
 * @param followSet  the set of FOLLOW of a non-terminal
 * @return Return a positive number for seen a token in firstSet.
 * @return Return a negative number for seen a token in followSet.
 * @return Return 0 for other cases.
 */
extern int parser_discard_tokens(t_parser_ptr pThis,
                          const EnumTokenKind * firstSet,
                          const EnumTokenKind * followSet);


// LookAhead:
// Peek the kind of next token,  equivalent to LOOK_AHEAD_K(pParser, 1)
#define LOOK_AHEAD(pParser)         token_get_kind((pParser)->pNextToken)

// LookAhead:
// Peek the kind of next Kth token
#define LOOK_AHEAD_K(pParser, k)    TOKENSTREAM_LA((pParser)->tokenStream, k)

// LookAhead:
// Peek the next token, equivalent to NEXT_TOKEN_K(pParser, 1)
#define NEXT_TOKEN(pParser)         ((pParser)->pNextToken)

// LookAhead:
// Peek the next Kth token
#define NEXT_TOKEN_K(pParser, k)    TOKENSTREAM_LT((pParser)->tokenStream, k)


/* -----------------------------------------------------------------------
       Recursive  Descent  Functions (RDF)
       ^          ^        ^

In AMCC, there are three groups of RDFs:
   - all expression,
   - all statements,
   - all declarations.

For each non-terminal X of AMC grammar, its RDF function is defined
according to the following rules:

1. The function is defined based on a template file "RDF.c.template.txt".
2. The function is saved in file "dir/\*.c". The "dir" may be:
   - decl: for all declaration constructs, and the file name is X.c
   - expr: for all expression constructs, and the file name is
           an abbreviation of X, such as primaryExpr.c, unaryExpr.c, etc.
   - stmt: for all statement constructs, and the file name is
           an abbreviation of X, such as jumpStmt.c, selectionStmt.c, etc.

3. The function prototype always is
        t_tree_ptr RDF_X (t_parser_ptr pThis).
4. The argument 'pThis' is a pointer to the current parser object.
5. The return value is :
   (1) On success, RDF_X() returns a parse tree which root-node is
       marked with non-terminal X, and all children are marked
       with grammar symbols of the production-right-part.
   (2) On any failure, such as bad input, memory allocation and so on,
       they return null.
       All errors will be reported immediately at the check point.

// -----------------------------------------------------------------------
*/


// declare RDFs for all non-terminals

#define  GRAM_NT_DEF(nt, n1, n2)  extern t_tree_ptr RDF_##nt (t_parser_ptr)
#define  GRAM_NT_DEF_SEP  ;
            #include "../meta/_gramsymbol.inc"
#undef   GRAM_NT_DEF
;



// Check whether 'newtree' is NULL or not.
// If true, tree 'root' will be destroyed,
// current function ABORTed abnormally (return a NULL tree)
#define CHECK_NULLTREE_ABORT(newtree, root)   do {      \
        if(NULL == (newtree)) {                         \
            if(NULL != (root)) {                        \
                tree_destroy(root); (root) = NULL ;     \
            }                                           \
            goto LABEL_EXIT_RDF;                        \
        } } while(0)



//#define   LOG_RDF_CALL       log_debug
#define LOG_RDF_CALL       log_without_header


AMCC_DECL_END

#endif //AMCC__PARSER_INNER_H
